package otSpaces.server.util;

import java.io.Serializable;
import java.math.BigInteger;

import com.sun.sgs.app.AppContext;
import com.sun.sgs.app.ManagedObject;
import com.sun.sgs.app.ManagedObjectRemoval;
import com.sun.sgs.app.ManagedReference;
import com.sun.sgs.app.ObjectNotFoundException;

public class AmbiguousReference<T> implements ManagedReference<T>, Serializable {

	public static class Managed<E> extends AmbiguousReference<E> implements
			ManagedObjectRemoval {

		private static final long serialVersionUID = -4852326002503796401L;

		public final boolean _remove;

		public Managed(E instance, final boolean remove) {
			super(instance);
			_remove = remove;
		}

		@Override
		public void removingObject() {
			if (_remove && _ref != null) {
				markForRemoval();
			}
		}

	}

	private static final long serialVersionUID = -390348143215104702L;

	public final T _direct;

	public final ManagedReference<T> _ref;

	public AmbiguousReference(T instance) {
		if (instance instanceof ManagedObject) {
			_direct = null;
			_ref = AppContext.getDataManager().createReference(instance);
		} else {
			_direct = instance;
			_ref = null;
		}
	}

	@Override
	public T get() {

		try {
			return _ref == null ? _direct : _ref.get();
		} catch (ObjectNotFoundException e) {
			return null;
		}
	}

	@Override
	public T getForUpdate() {
		final T ret = get();

		if (ret != null && _ref != null) {
			AppContext.getDataManager().markForUpdate(ret);
		}

		return ret;
	}

	@Override
	public BigInteger getId() {
		if (_ref == null) {
			throw new UnsupportedOperationException();
		} else {
			return _ref.getId();
		}
	}

	public void markForRemoval() {
		if (_ref != null) {
			try {
				AppContext.getDataManager().removeObject(_ref.get());
			} catch (ObjectNotFoundException e) {
				// I don't care
			}
		}
	}
}
